/*
 * @Author: 缄默
 * @Date: 2021-12-12 15:17:45
 * @LastEditors: 缄默
 * @LastEditTime: 2021-12-29 18:19:59
 */

//观察者模式
#include <iostream>
#include <vector>
#include <list>

using namespace std;

class Observer { 
public:
    virtual ~Observer() { }

    virtual void update(string& state) = 0;
};


class Subjective { 
public:
    virtual ~Subjective() { }

    virtual void attach(Observer* ob) = 0;

    virtual void detach(Observer* ob) = 0;

    virtual void notify() = 0;

    virtual void setState(string& state) = 0;

    virtual string getState() = 0;

protected:
    list<Observer*> _observers;
    
};


class ConcreteSubjective : public Subjective { 
private:
    string _state;
public:

    ConcreteSubjective() {
        _state = "default";
    }

    void setState(string& state) {
        if (state != _state) {
            _state = state;
            notify();
        }
    }

    string getState() {
        return _state;
    }
    
    void attach(Observer* obs) {
        _observers.emplace_back(obs);
    }

    void detach(Observer* obs) {
        _observers.remove(obs);
    }

    void notify() {
        for (auto x : _observers) {
            x->update(_state);
        }
    }
};

class ConcreteObserver1 : public Observer { 
private:

public:
    void update(string& state) {
        cout << "ConcreteObsrever1...   " << state << endl;
    }
};

class ConcreteObserver2 : public Observer { 
private:
public:
    void update(string& state) {
        cout << "ConcreteObsrever2...   " << state << endl;
    }   
};

class ConcreteObserver3 : public Observer { 
private:
public:
    void update(string& state) {
        cout << "ConcreteObsrever3...   " << state << endl;
    }    
};

int main() {
    Subjective* sub = new ConcreteSubjective();
    Observer* obs1 = new ConcreteObserver1();
    Observer* obs2 = new ConcreteObserver2();
    Observer* obs3 = new ConcreteObserver3();

    sub->attach(obs1);
    sub->attach(obs2);
    sub->attach(obs3);

    sub->notify();
    string s1 = "new";
    sub->setState(s1);
    s1 = "old";
    sub->setState(s1);
    sub->detach(obs1);

    s1 = "new";
    sub->setState(s1);

    delete sub;
    delete obs1;
    delete obs2;
    delete obs3;

    return 0;
}